 #include "stdafx.h"
#include "Decode.h"
#include "CheckCode.h"
#include "FindCode.h"


static int g_code[96][6];
static float g_possibility[96][6];
static std::string g_filenameAppend;


//************************************
// Method:    	getDots
// FullName:  	Decode::getDots
// Access:    	public 
// Returns:   	void
// Parameter: 	IplImage * img
// Parameter: 	IplImage * normalized
// Parameter: 	int type
// Description:	Main Method for extracting the code
//************************************
void Decode::getDots(IplImage *img, IplImage *normalized, int type, std::string filename, int part, int ammount)
{
	for (int i=0; i<96; i++)
	{
		for (int j=0; j<6; j++)
		{
			g_code[i][j]=0;
			g_possibility[i][j]=0;
		}
	}


	//possition of code known. This construction lays a grid over the code (3 times 32x6)
	for (int i=0; i<3; i++)
	{
		for (int j=0; j<32; j++)
		{
			int xCoord;
			int yCoord;
			int thresh=0;
			CvPoint startPix;
			int count2 = 0;
			int jnew = j;
	
			if (type == 1)
				jnew = -1 * (j-31);

			//determine posibilities for each grid in a row
			for (int k=0; k<6; k++)
			{
				xCoord = 152*i + k*22 + 1;
				yCoord = jnew*21.8 + 1;
				startPix = cvPoint(xCoord,yCoord);
				float count = getCol(normalized,startPix);
				g_possibility[i*32+j][k] = count;
				count2 += count;					
			}

			thresh = checkRowPossib(i*32+j);

			count2 = count2 / 6;

			//determine if its a dot or not
			for (int l=0; l<6; l++)
			{
				xCoord = 152*i + l*22 + 1;
				yCoord = jnew*21.8 + 1;
				startPix = cvPoint(xCoord,yCoord);
				if(/*isDot(normalized,startPix)*/g_possibility[i*32+j][l]>g_possibility[i*32+j][0]/2 || l==0 /*&&  Decode::getCol(normalized,startPix) && Decode::matchTemplate(img,startPix)*/)
				{
					g_code[i*32+j][l] = 1;
				}
				else 
				{
					g_code[i*32+j][l] = 0;
				}
			}

			//TODO -> fix!
			
			int fixRows[] = {0,8,15,23,29,31,32,38,43,48,53,58,63,64,71,78,83,87,89,95};
			for (int l=0; l<sizeof(fixRows)/sizeof(fixRows[0]); l++)
			{
				for (int m=0; m<6; m++)
					g_code[fixRows[l]][m]=1;
			}
							
		}
	}


	//test
	if (Init::getDebug())
	{
		for (int i=0; i<96; i++)
		{
			cout<<i+1<<":";
			for (int j=0; j<6; j++)
			{
				cout<<g_code[i][j]<<"-";
			}
			cout<<endl;
		}
	}

	/*for (int i=0; i<96; i++)
	{
		cout<<i+1<<":";
		for (int j=0; j<6; j++)
		{
			cout<<g_possibility[i][j]<<"-";
		}
		cout<<"\n";
	}*/

	if(Init::getDebug())
	{
		cvNamedWindow("Binary Codeblock", 1);
		cvShowImage("Binary Codeblock", normalized);
		cvWaitKey(0);
		cvDestroyWindow("Binary Codeblock");
	}
	

	CheckCode::check(filename,ammount-part);


	decipherCode(filename,ammount-part,type);

}


//************************************
// Method:    checkRowPossib
// FullName:  Decode::checkRowPossib
// Access:    private static 
// Returns:   int
// Parameter: int row
// !METHOD ATM UNUSED!
//************************************
int Decode::checkRowPossib(int row)
{
	float temp[6];
	int min;
	float maxdist, temp2, minval, maxval;
	for (int i=0; i<6; i++)
		temp[i]=g_possibility[row][i];


	for (int i=0; i<5; i++)
	{
		min=i;
		for (int j=i; j<6; j++)
		{
			if (temp[j]<temp[min])
			{
				min=j;
			}
		}
		temp2=temp[min];
		temp[min]=temp[i];
		temp[i]=temp2;
	}

	
	maxdist=temp[1]-temp[0];
	minval=temp[0];
	maxval=temp[1];
	for (int i=1; i<5; i++)
	{
		if (maxdist < (temp[i+1]-temp[i]))
		{
			minval=temp[i];
			maxval=temp[i+1];
			maxdist = temp[i+1]-temp[i];
		}
	}
	return 1;
}




//************************************
// Method:    	getValue
// FullName:  	Decode::getValue
// Access:    	public 
// Returns:   	int
// Parameter: 	int dim1
// Parameter: 	int dim2
// Description:	getter function for code
//************************************
int Decode::getValue(int dim1, int dim2)
{
	return g_code[dim1][dim2];
}



//************************************
// Method:    	getPossibility
// FullName:  	Decode::getPossibility
// Access:    	public 
// Returns:   	float
// Parameter: 	int dim1
// Parameter: 	int dim2
// Description:	getter function for possibility
//************************************
float Decode::getPossibility(int dim1, int dim2)
{
	return g_possibility[dim1][dim2];
}



//************************************
// Method:    	setValue
// FullName:  	Decode::setValue
// Access:    	public 
// Returns:   	void
// Parameter: 	int dim1
// Parameter: 	int dim2
// Parameter: 	int val
// Description:	setter function for code
//************************************
void Decode::setValue(int dim1, int dim2, int val)
{
	g_code[dim1][dim2]=val;
}


//************************************
// Method:    	isDot
// FullName:  	Decode::isDot
// Access:    	private static 
// Returns:   	bool
// Parameter: 	IplImage * img
// Parameter: 	CvPoint startPix
// Description:	calculates the median for one grid-field
//************************************
bool Decode::isDot(IplImage *img, CvPoint startPix)
{
	int pixVal[225];
	for (int i=0; i<225; i++)
		pixVal[i]=0;

	int min, average;

	//just for debuging
	if(Init::getDebug())
	{
		cvRectangle(img,cvPoint(startPix.x,startPix.y),cvPoint(startPix.x+22,startPix.y+22),cvScalar(255,255,255,0),1,8,0);
	}

	//running through field, saving each pixel value
	for (int i=4; i<=18; i++)
	{
		int y = startPix.y+i;
		for (int j=4; j<=18; j++)
		{	
			int x = startPix.x+j;
			Pixel pix = ImageUtils::getPixel(img,x,y);
			pixVal[(15*(i-4))+(j-4)] = pix.getValue();
		}
	}
	
	//calculate median
	for (int i = 0; i < 225; i++){
		min = i;
		for (int j = i+1; j < 225; j++){
			if (pixVal[j] < pixVal[min]){
				min	= j;
			}
			if (min != i){
				int tmp;
				tmp = pixVal[i];
				pixVal[i] = pixVal[min];
				pixVal[min] = tmp;	
			}	
		}
	}
	int median = pixVal[112];
	/*
	int maxPartX = Init::getParts().y;
		int maxPartY = Init::getParts().x;
		int actPart = 0;
	
		for (int i=0; i<maxPartY; i++)
		{
			for (int j=0; j<maxPartX; j++)
			{
				if (startPix.x >= j*(img->width/maxPartX) && startPix.x <(j+1)*(img->width/maxPartX) &&
					startPix.y >= i*(img->height/maxPartY) && startPix.y <(i+1)*(img->height/maxPartY))
					actPart=j+(i*maxPartX);
	
			}
		}*/
	
	if (median >= 255)
		return true;

	return false;
}



//************************************
// Method:    	getCol
// FullName:  	Decode::getCol
// Access:    	private static 
// Returns:   	float
// Parameter: 	IplImage * img
// Parameter: 	CvPoint startPix
// Description:	counts white pixel in image
//************************************
float Decode::getCol(IplImage *img, CvPoint startPix)
{
	float count=0, count2=0;
	float pixValue=0;

	for (int l=1; l<=20; l++)
	{
		int y = l+startPix.y;
		for (int m=1; m<=19; m++)
		{
			count2++;
			int x = m+startPix.x;
			if (x < img->width && y < img->height)
			{
				Pixel pix = ImageUtils::getPixel(img,x,y,img->nChannels);
				pixValue=pix.getValue();
				count+=pixValue/765;
			}
		}
	}

	//return value from 0-1
	return count/count2;
}



//************************************
// Method:    	matchTemplate
// FullName:  	Decode::matchTemplate
// Access:    	private static 
// Returns:   	bool
// Parameter: 	IplImage * test
// Parameter: 	CvPoint startPix
// Description:	matching each grid field with a template
//	!ATM UNUSED!
//************************************
bool Decode::matchTemplate(IplImage *test, CvPoint startPix)
{
	double minVal, maxVal;
	CvPoint minLoc;
	CvPoint maxLoc;

	cvSetImageROI(test,cvRect(startPix.x,startPix.y,20,20));

	IplImage *templ = cvLoadImage("dot.tif",0);
	IplImage *templResult = cvCreateImage(cvSize(20 - templ->width + 1, 20 - templ->height + 1), IPL_DEPTH_32F, 1);
	
	cvMatchTemplate(test, templ, templResult, CV_TM_CCOEFF);
	cvMinMaxLoc(templResult, &minVal, &maxVal, &minLoc, &maxLoc); 
	
	cvResetImageROI(test);
	cvSetImageROI(test,cvRect(maxLoc.x,maxLoc.y,430,700));
	cvReleaseImage(&templ);
	cvReleaseImage(&templResult);
	if (maxVal > 5000)
		return true;
	else
		return false;
}


//************************************
// Method:    	decipherCode
// FullName:  	Decode::decipherCode
// Access:    	private static 
// Returns:   	void
// Description:	transforms binary code to readable info
//************************************
void Decode::decipherCode(std::string filename, int part,int type)
{

	std::string st(Init::getPath());
	ofstream output;


	//replace "\" with "/"
	for (int i=0; i<st.size(); i++)
	{
		if (st[i]=='\\')
			st[i]='/';
	}
	//appending all the stuff for a valid path
	st+=Init::getDataDir();
	st+="/data.csv";

	char temp[512]="";
	double time[4]; //{h,m,s}
	double lattitude[3]; //{+/-,deg,min}
	double longitude[3]; //+/-,deg,min}
	double date[3]; //{d,m,y}
	double taskingUnit[2]; //{Running Num., Tasking Unit}
	double distance, altitude, heading, drift, roll,
		pitch, speed, lensPos, evnt, senID;


	time[3] = add(1);
	time[2] = add(2) + add(3)*10;
	time[1] = add(4) + add(5)*10;
	time[0] = add(6) + add(7)*10;


	lattitude[0] = add(9);
	lattitude[2] = add(10)/10 + add(11) + add(12)*10;
	lattitude[1] = add(13) + add(14)*10;
	

	longitude[0] = add(16);
	longitude[2] = add(17)/10 + add(18) + add(19)*10;
	longitude[1] = add(20) + add(21)*10 + add(22)*100;



	distance = add(24) + add(25)*10 + add(26)*100 + add(27)*1000 +
		add(28)*10000;


	altitude = add(33) + add(34)*10 + add(35)*100 + add(36)*1000 +
		add(37)*10000;


	heading = add(39)/10 + add(40) + add(41)*10 + add(42)*100;


	drift = add(44) * ((add(45)/10) + add(46) + add(47)*10);


	roll = add(49) * ((add(50)/10) + add(51) + add(52)*10);


	pitch = add(54) * ((add(55)/10) + add(56) + add(57)*10);


	speed = add(59) + add(60)*10 + add(61)*100 + add(62)*1000;


	date[0] = add(65) + add(66)*10;
	date[1] = add(67) + add(68)*10;
	date[2] = add(69) + add(70)*10;

	taskingUnit[0] = add(72) + add(73)*10 + add(74)*100;
	taskingUnit[1] = add(75) + add(76)*10 + add(77)*100;


	lensPos = add(79) * (add(80) + add(81)*10);


	evnt = add(84) + add(85)*10;


	senID = add(88);	
	
	std::stringstream out;
	if (date[2]<50)
	{
		date[2]<10 ? out<<"200"<<date[2] : out<<"20"<<date[2];
	} else if (date[2]>=50)
	{
		out<<"19"<<date[2];
	}
	date[1]<10 ? out<<"0"<<date[1] : out<<date[1];
	date[0]<10 ? out<<"0"<<date[0] : out<<date[0];
	time[0]<10 ? out<<"0"<<time[0] : out<<time[0];
	time[1]<10 ? out<<"0"<<time[1] : out<<time[1];
	time[2]<10 ? out<<"0"<<time[2] : out<<time[2];
	time[3]<10 ? out<<"0"<<time[3]<<"_" : out<<time[3]<<"_";
	Init::setFilenameAppend(out.str());
	
	output.open(st.c_str(),ios::app);
	if (type==1 && part>1)
		part<10 ? output<<out.str()<<"_"<<filename<<"_0"<<part<<"NTR," : output<<out.str()<<"_"<<filename<<"_"<<part<<"NTR,";
	else if (type==0 && part>1)
		part<10 ? output<<out.str()<<"_"<<filename<<"_0"<<part<<"NTE," : output<<out.str()<<"_"<<filename<<"_"<<part<<"NTE,";
	else if (type==1 && part<=1)
		part<10 ? output<<out.str()<<"_"<<filename<<"_NTR," : output<<out.str()<<"_"<<filename<<"_NTR,";
	else if (type==0 && part<=1)
		part<10 ? output<<out.str()<<"_"<<filename<<"_NTE," : output<<out.str()<<"_"<<filename<<"_NTE,";

	std::stringstream data;
	
	data<<(int)time[0]<<":"<<(int)time[1]<<":"<<(int)time[2]<<":"<<(int)time[3]<<",";
	data<<(int)(lattitude[0]*lattitude[1])<<"."<<(int)((lattitude[2]/60)*10)<<",";
	data<<(int)(longitude[0]*longitude[1])<<"."<<(int)((longitude[2]/60)*10)<<",";
	data<<distance<<",";
	data<<altitude<<",";
	data<<heading<<",";
	data<<drift<<",";
	data<<roll<<",";
	data<<pitch<<",";
	data<<speed<<",";
	data<<(int)date[0]<<"/"<<(int)date[1]<<"/"<<(int)date[2]<<",";
	data<<(int)taskingUnit[1]<<",";
	data<<lensPos<<",";
	data<<evnt<<",";
	data<<senID;


	

	//test
	if(Init::getDebug())
	{
		cout<<"\nTime: "<<time[0]<<":"<<time[1]<<":"<<time[2]<<":"<<time[3]<<endl;
		cout<<"Lattitude: "<<lattitude[0]*lattitude[1]<<"deg "<<lattitude[2]<<"'"<<endl;
		cout<<"Longitude: "<<longitude[0]*longitude[1]<<"deg "<<longitude[2]<<"'"<<endl;
		cout<<"Distance: "<<distance<<"m"<<endl;
		cout<<"Altitude: "<<altitude<<"ft"<<endl;
		cout<<"Heading: "<<heading<<"deg"<<endl;
		cout<<"Drift: "<<drift<<"deg"<<endl;
		cout<<"Roll: "<<roll<<"deg"<<endl;
		cout<<"Pitch: "<<pitch<<"deg"<<endl;
		cout<<"Speed: "<<speed<<"kts"<<endl;
		cout<<"Date: "<<date[0]<<"/"<<date[1]<<"/"<<date[2]<<endl;
		cout<<"TalkingUnit: "<<taskingUnit[0]<<"//"<<taskingUnit[1]<<endl;
		cout<<"LensPosition: "<<lensPos<<"deg"<<endl;
		cout<<"Event: "<<evnt<<endl; 
		cout<<"SenID: "<<senID<<endl;
	}

	output<<data.str()<<endl;
	output.close();

	
	


}

std::string getFilenameAppend()
{
	return g_filenameAppend;
}







//************************************
// Method:    	decipherCode
// FullName:  	Decode::decipherCode
// Access:    	private static 
// Returns:   	void
// Description:	transforms binary code to readable info
//				OUTPUT IN XML! ASKED FOR: CSV
//				not deleted in case, someone in the future asks for XML output
//************************************
/*

#include "tinyxml.h"
#include "tinystr.h"
void Decode::decipherCode()
{

	TiXmlDocument doc;
	TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
	doc.LinkEndChild( decl );
	
	TiXmlElement * element;
	TiXmlText * text;

	
	char temp[512]="";
	double time[3]; //{h,m,s}
	double lattitude[3]; //{+/-,deg,min}
	double longitude[3]; //+/-,deg,min}
	double date[3]; //{d,m,y}
	double taskingUnit[2]; //{Running Num., Tasking Unit}
	double distance, altitude, heading, drift, roll,
		pitch, speed, lensPos, evnt, senID;

	
	time[2] = add(1)/10 + add(2) + add(3)*10;
	time[1] = add(4) + add(5)*10;
	time[0] = add(6) + add(7)*10;
		/ *element = new TiXmlElement( "Time" );
		doc.LinkEndChild( element );* /
	TiXmlElement * root = new TiXmlElement("Codeblock");
	doc.LinkEndChild(root);
	root->SetAttribute("Hour",time[0]);
	root->SetAttribute("Min",time[1]);
	root->SetAttribute("Sec",time[2]);
	sprintf( temp, "%d-%d-%d",(int)time[0],(int)time[1],(int)time[2]);
	/ *
	text = new TiXmlText( temp );
		element->LinkEndChild( text );* /
	

	

	lattitude[0] = add(9);
	lattitude[2] = add(10)/10 + add(11) + add(12)*10;
	lattitude[1] = add(13) + add(14)*10;
	element = new TiXmlElement( "Lattitude" );
	
	sprintf( temp, "%ddeg %dmin",(int)(lattitude[0]*lattitude[1]),(int)lattitude[2]);
	element->LinkEndChild( new TiXmlText( temp ) );
	root->LinkEndChild(element);

	longitude[0] = add(16);
	longitude[2] = add(17)/10 + add(18) + add(19)*10;
	longitude[1] = add(20) + add(21)*10 + add(22)*100;
	element = new TiXmlElement( "Longitude" );
	sprintf( temp, "%ddeg %dmin",(int)(longitude[0]*longitude[1]),(int)longitude[2]);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);



	distance = add(24) + add(25)*10 + add(26)*100 + add(27)*1000 +
		add(28)*10000;
	element = new TiXmlElement( "Distance" );

	sprintf( temp, "%d",(int)distance);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	altitude = add(33) + add(34)*10 + add(35)*100 + add(36)*1000 +
		add(37)*10000;
	element = new TiXmlElement( "Altitude" );
	sprintf( temp, "%d",(int)altitude);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	heading = add(39)/10 + add(40) + add(41)*10 + add(42)*100;
	element = new TiXmlElement( "Heading" );
	sprintf( temp, "%f",heading);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	drift = add(44) * (add(45)/10) + add(46) + add(47)*10;
	element = new TiXmlElement( "Drift" );
	sprintf( temp, "%f",drift);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	roll = add(49) * (add(50)/10) + add(51) + add(52)*10;
	element = new TiXmlElement( "Roll" );
	sprintf( temp, "%f",roll);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	pitch = add(54) * (add(55)/10) + add(56) + add(57)*10;
	element = new TiXmlElement( "Pitch" );
	sprintf( temp, "%f",pitch);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	speed = add(59) + add(60)*10 + add(61)*100 + add(62)*1000;
	element = new TiXmlElement( "Speed" );
	sprintf( temp, "%d",(int)speed);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	date[0] = add(65) + add(66)*10;
	date[1] = add(67) + add(68)*10;
	date[2] = add(69) + add(70)*10;
	element = new TiXmlElement( "Date" );
	sprintf( temp, "%d-%d-%d",(int)date[0],(int)date[1],(int)date[2]);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	taskingUnit[0] = add(72) + add(73)*10 + add(74)*100;
	taskingUnit[1] = add(75) + add(76)*10 + add(77)*100;
	element = new TiXmlElement( "TaskingUnit" );
	sprintf( temp, "%d",(int)taskingUnit[1]);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);

	element = new TiXmlElement( "RunningNumber" );
	sprintf( temp, "%d",(int)taskingUnit[0]);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	lensPos = add(79) * (add(80) + add(81)*10);
	element = new TiXmlElement( "LensPosition" );
	sprintf( temp, "%d",(int)lensPos);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	evnt = add(84) + add(85)*10;
	element = new TiXmlElement( "Event" );
	sprintf( temp, "%d",evnt);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);


	senID = add(88);
	element = new TiXmlElement( "SenID" );
	sprintf( temp, "%d",(int)senID);
	text = new TiXmlText( temp );
	element->LinkEndChild( text );
	root->LinkEndChild(element);



	//test
	if(Init::getDebug())
	{
		cout<<"Time: "<<time[0]<<":"<<time[1]<<":"<<time[2]<<endl;
		cout<<"Lattitude: "<<lattitude[0]*lattitude[1]<<"deg "<<lattitude[2]<<"'"<<endl;
		cout<<"Longitude: "<<longitude[0]*longitude[1]<<"deg "<<longitude[2]<<"'"<<endl;
		cout<<"Distance: "<<distance<<"m"<<endl;
		cout<<"Altitude: "<<altitude<<"ft"<<endl;
		cout<<"Heading: "<<heading<<"deg"<<endl;
		cout<<"Drift: "<<drift<<"deg"<<endl;
		cout<<"Roll: "<<roll<<"deg"<<endl;
		cout<<"Pitch: "<<pitch<<"deg"<<endl;
		cout<<"Speed: "<<speed<<"kts"<<endl;
		cout<<"Date: "<<date[0]<<"/"<<date[1]<<"/"<<date[2]<<endl;
		cout<<"TalkingUnit: "<<taskingUnit[0]<<"//"<<taskingUnit[1]<<endl;
		cout<<"LensPosition: "<<lensPos<<"deg"<<endl;
		cout<<"Event: "<<evnt<<endl; 
		cout<<"SenID: "<<senID<<endl;
	}
	

	std::string st(Init::getPath());
	//stringstream for appending int
	std::stringstream out;

	//replace "\" with "/"
	for (int i=0; i<st.size(); i++)
	{
		if (st[i]=='\\')
			st[i]='/';
	}
	//appending all the stuff for a valid path
	st+=Init::getDataDir();
	st+="/";

	//making a filename with date&time from codeblock/image
	for (int i=0; i<3; i++)
	{
		out<<date[i];
		out<<"-";
	}
	for (int i=0; i<3; i++)
	{
		out<<"-";
		out<<(int)time[i];
	}

	st+=out.str();
	st+=".xml";

	//save file
	doc.SaveFile(st.c_str());
}*/



/**************************************************************************
** add() - adding bit 1 to 4 of nibble based on given data matrix coding **
** 0 = "Not used"														 **
** 1 = "Minus sign"														 **
** 3 = "Error"															 **
** 4-12 = "0-9"															 **
** 13 = "Plus sign"														 **
** 14 = "Special"														 **
** 15 = "Divider"														 **
***************************************************************************/
double Decode::add(int pos)
{
	double sum = (g_code[pos][4]+2*g_code[pos][3]+4*g_code[pos][2]+8*g_code[pos][1])-3;
	if (sum == -2)
		return -1;
	else if (sum == -1)
		return -2;
	else if (sum == 10)
		return 1;
	else 
		return sum;
}
